/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __DEBUG_PRINT_H__
#define __DEBUG_PRINT_H__

#include "BaseType.h"
#include "Singleton.h"
#include "Thread.h"
#include "ThreadUtil.h"
#include "FileUtil.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <iostream>
#include <typeinfo>

/**
 *  \file   Tracer.h   
 *  \brief  调试用跟踪打印类
 *  \note   等级越高越容易打印,高于当前打印等级的都能打印出来
 *		    如当前级别为1，则DBG(0)等级的信息不会被打印出来,大
 *		    于当前等级的信息都能打印出来.默认为INFO(1)等级.
 */

#define BUILD_REL_VERSION			0	/* 打开后只打印ERR和REL级别的打印 */

//===>打印等级说明:只有大于或等于当前打印等级的消息才能被打印!
#define TRACE_LEVEL_DBG             0       /**< 用于调试信息的打印 */
#define TRACE_LEVEL_INFO            1       /**< 用于重点提示信息的打印 */
#define TRACE_LEVEL_WARN            2       /**< 用于警告信息打印 */
#define TRACE_LEVEL_ERR             3       /**< 用于错误信息的打印 */
#define TRACE_LEVEL_REL             4       /**< 用于用户信息的打印 */

/** linux标准错误字串 */
#define ERRSTR				(strerror(errno))
#define ERRMSG(err)			(strerror(err))
#define PRINTF(fmt,...)     do{printf(fmt,##__VA_ARGS__);}while(0)	/* __VA_ARGS__宏是C99标准定义的 */


/** 颜色打印 */
#define TRACE_RED(fmt,arg...)       do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[31m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_GREEN(fmt,arg...)     do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[32m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_YELLOW(fmt,arg...)    do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[33m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_PINK(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[35m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_CYAN(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[36m\033[1m" fmt "\033[0m",##arg);}while(0)
/** 下面宏实现可以根据信息类型分颜色打印 */
#define TRACE_D(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_DBG,"\033[36m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_R(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,fmt,##arg);}while(0)
#define TRACE_E(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_ERR,"\033[31m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_W(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_WARN,"\033[33m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_I(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_INFO,"\033[32m\033[1m" fmt "\033[0m",##arg);}while(0)
/** 打印16进制字串 */
#define TRACE_HEX(tag,buf,len)      do{libemb::Tracer::getInstance().printHex(TRACE_LEVEL_DBG, tag, buf, len);}while(0)
#define TRACE_TEXT(fmt,arg...)      do{if(libemb::Tracer::getInstance().getLevel()==TRACE_LEVEL_DBG){\
                                       TRACE_CYAN("----------------------------------------\n");\
                                       printf(fmt,arg);\
                                       TRACE_CYAN("\n----------------------------------------\n");\
                                    }}while(0)

/** 按消息级别打印 */
#define TRACE_DBG(fmt,arg...)       {TRACE_D("<DEBUG@%s,L%d>:" fmt,__FUNCTION__,__LINE__,##arg);}
#define TRACE_INFO(fmt,arg...)      {TRACE_I("<INFO @%s,L%d>:" fmt,__FUNCTION__,__LINE__,##arg);}
#define TRACE_WARN(fmt,arg...)      {TRACE_W("<WARN @%s,L%d>:" fmt,__FUNCTION__,__LINE__,##arg);}
#define TRACE_ERR(fmt,arg...)       {TRACE_E("<ERROR@%s,L%d>:" fmt,__FUNCTION__,__LINE__,##arg);}
#define TRACE_REL(fmt,arg...)       {TRACE_R("<REL  @%s>:" fmt,__FUNCTION__,##arg);}


/** 带类名的级别打印(仅在C++类中可使用,需要this指针) */
#define CLASS_NAME(classPtr)         (&(typeid(*classPtr).name()[1]))
#define TRACE_DBG_CLASS(fmt,arg...)     {TRACE_D("[%-10s]<DEBUG@%s,L%d>:" fmt,CLASS_NAME(this),__FUNCTION__,__LINE__,##arg);}
#define TRACE_INFO_CLASS(fmt,arg...)    {TRACE_I("[%-10s]<INFO >:" fmt,CLASS_NAME(this),##arg);}
#define TRACE_WARN_CLASS(fmt,arg...)    {TRACE_W("[%-10s]<WARN @%s,L%d>:" fmt,CLASS_NAME(this),__FUNCTION__,__LINE__,##arg);}
#define TRACE_ERR_CLASS(fmt,arg...)     {TRACE_E("[%-10s]<ERROR@%s,L%d>:" fmt,CLASS_NAME(this),__FUNCTION__,__LINE__,##arg);}
#define TRACE_REL_CLASS(fmt,arg...)     {TRACE_R("[%-10s]" fmt,CLASS_NAME(this),##arg);}

/** 下面的宏用于调试跟踪 */
#define TRACE_IF(condition)         do{if((condition)){TRACE_RED("if(%s)<@%s,L%d>\n",#condition,__FUNCTION__,__LINE__);};}while(0)
#define TRACE_IF_CLASS(condition)   do{if((condition)){TRACE_RED("if(%s)<@%s,L%d>[%s]\n",#condition,__FUNCTION__,__LINE__,CLASS_NAME(this));};}while(0)
#define TRACE_NONE(fmt,arg...)

#define TRACE_ASSERT(condition)  (if(!(condition)){TRACE_ERR("Assert !!!\n");while(1){libemb::Thread::msleep(100);}})

#if BUILD_REL_VERSION
#include "TracerLess.h"
#endif

using TracerCmdExecutor = std::function<void(const char*)>;

namespace libemb{
class Tracer:public Singleton<Tracer>{
	DECL_SINGLETON(Tracer)
	{
		m_printBuf = std::make_unique<char[]>(TRACE_MAXLEN);
		setvbuf(stdout, NULL, _IONBF, BUFSIZ);
	}
public:
    ~Tracer(){};
    void print(int level,const char* format,...);
    void setLevel(int level);
    int getLevel();
	bool isDebuging();
    void printHex(int level,const char* tag,const char* buf,int len);
	bool fileOut(bool enable,const char* fileName=NULL);/* 日志重定向到文件 */
	bool ttyRemote(const char* remoteMsg, int len,TracerCmdExecutor callcmd=NULL);
private:
	static const int TRACE_MAXLEN =4096;/* 打印长度最大为4096Bytes,超出后显示省略号 */
	std::unique_ptr<char[]> m_printBuf;
	std::unique_ptr<File> m_traceFile;
    int m_traceLevel{TRACE_LEVEL_INFO};
	int m_remoteLevel{TRACE_LEVEL_REL};
	
};
}
#endif



